﻿/*
 * 施耐德干式变压器温度控制
 * changli.xiao
 * 2014/1/18
 * 
*/
 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using JN.Utility;
using System.IO.Ports;
using Power.Common;
using System.Data;

namespace Power.TemperControl
{
    public class TemperatureController
    {
        #region property
        public delegate void UpdateStatusHandler(MsgType msgType, object msg);
        public static event UpdateStatusHandler UpdateStatus;

        private Thread readThread;
        private object lockRead = new object();
        private Thread doProcessThread;
        private object lockDoProcess = new object();
        private Manager.SystemStatus sysStatus = Manager.SystemStatus.Instance;
        private MeterControl.MeterCommon portComm = MeterControl.MeterCommon.Instance;
        private List<SerialPort> listCom = new List<SerialPort>();   //用于记录所有的serialport
        private List<Meter_Str> listTempData = new List<Meter_Str>();  //用于记录临时数据
        private List<string> listHead = new List<string>();    //用于记录电表head
        private List<int> listNode = new List<int>();      //用于记录多少节点
        private int cur_hour = -1;  //当前小时

        private DataTable dtMeter;
        BLL.Meter_infoBLL meterBLL = new BLL.Meter_infoBLL();
        BLL.Com_infoBLL comBLL = new BLL.Com_infoBLL();
        BLL.Thermostat_rBLL realDataBLL = new BLL.Thermostat_rBLL();

        #endregion
        private static TemperatureController instance = null;
        private static readonly object plcLock = new object();
        public static TemperatureController Instance
        {
            get
            {
                lock (plcLock)
                {
                    if (instance == null)
                    {
                        instance = new TemperatureController();
                    }
                    return instance;
                }
            }
        }

        private TemperatureController()
        {
        }
        private void StartThread()
        {
            if (readThread == null)
            {
                readThread = new Thread(new ThreadStart(ReadTemp));
                readThread.Name = "Temperature Read Thread";
                readThread.IsBackground = true;
                readThread.Start();
            }
        }
        private void ReadTemp()
        {
            while (true)
            {
                if (sysStatus.IsStartRead)
                {
                    ReadFun();
                }
                else
                {
                    Thread.Sleep(1000);
                }
            }
        }
        private void ReadFun()
        {
            lock (lockRead)
            {
                DateTime startTime = DateTime.Now;
                try
                {
                    //1. get this sation com port list
                    GetCommPort();
                    //2. open all port
                    if (listCom.Count <= 0)
                    {
                        SystemLogger.Write(LogType.Error, "Error: Com port is none", "ReadFun");
                        Common.Notify.NotifyMessage.Show("系统错误", "系统设定COM端口错误", true);
                        return;
                    }
                    if (listCom.Count != listHead.Count && listCom.Count != listNode.Count)
                    {
                        SystemLogger.Write(LogType.Error, "Error: Com data length error. com count:" + listCom.Count + " head count:" + listHead.Count + " node count:" + listNode.Count, "ReadFun");
                        Common.Notify.NotifyMessage.Show("系统错误", "系统设定错误. com count" + listCom.Count + " head count:" + listHead.Count + " node count:" + listNode.Count, true);
                        return;
                    }
                    //3. loop all port/all node read current data from one port,save to list
                    for (int i = 0; i < listCom.Count; i++)
                    {
                        string revMessage = "";
                        string writeData = "";
                        //string paramData = "";
                        string revParaData = "";
                        bool ret;
                        SerialPort temport = listCom[i];
                        for (int j = 0; j < listNode[i]; j++)
                        {                           
                            string x = (j + 1).ToString("X");
                            writeData = listHead[i].Replace("##", x.PadLeft(2, '0'));
                            ret = portComm.Write(temport, writeData, ref revMessage);
                            if (!ret)
                            {
                                SystemLogger.Write(LogType.Error, "Error,Read Com Data Failed." + temport.PortName + "-" + writeData, "ReadFun");
                                //Read_Failed failed_data = new Read_Failed();
                                //failed_data.Com_Port = temport.PortName;
                                //failed_data.Node = j + 1;
                                //listReadFilaed.Add(failed_data);
                            }
                            else
                            {
                                //add to list
                                Meter_Str temp = new Meter_Str();
                                temp.Com_Port = temport.PortName;
                                temp.Meter_Data = revMessage;
                                temp.Param_Data = revParaData;
                                listTempData.Add(temp);
                            }
                            
                        }
                    }

                }
                catch (Exception ex)
                {
                    SystemLogger.Write(ex);
                }
                finally
                {
                    TimeSpan useTime = DateTime.Now - startTime;
                    SystemLogger.Write(LogType.Flow, "Temperature one flow use time:" + useTime.TotalMilliseconds, "ReadFun");
                    //4. do sleep                     
                    Thread.Sleep(1000);
                }
            }
        }
        public void GetCommPort()
        {
            try
            {
                if (sysStatus.IsChangCom)
                {
                    //clear all data
                    listCom.Clear();
                    listHead.Clear();
                    listNode.Clear();

                    StringBuilder sql = new StringBuilder();
                    sql.Append(" station_id='" + sysStatus.Station_id + "' and scan_cycle=2 ");
                    DataTable dt = comBLL.GetList(sql.ToString()).Tables[0];
                    if (dt.Rows.Count <= 0) return;
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        try
                        {
                            //get port info
                            SerialPort port = new SerialPort();
                            port.PortName = dt.Rows[i]["com_port"].ToString();
                            port.BaudRate = int.Parse(dt.Rows[i]["baud_rate"].ToString());
                            port.DataBits = int.Parse(dt.Rows[i]["data_bit"].ToString());
                            switch (dt.Rows[i]["odd"].ToString().ToUpper())
                            {
                                case "NONE":
                                    port.Parity = Parity.None;
                                    break;
                                case "ODD":
                                    port.Parity = Parity.Odd;
                                    break;
                                case "EVEN":
                                    port.Parity = Parity.Even;
                                    break;
                            }
                            switch (dt.Rows[i]["stop_bit"].ToString())
                            {
                                case "1":
                                    port.StopBits = StopBits.One;
                                    break;
                                case "1.5":
                                    port.StopBits = StopBits.OnePointFive;
                                    break;
                                case "2":
                                    port.StopBits = StopBits.Two;
                                    break;
                            }
                            port.ReadTimeout = 500;
                            port.WriteTimeout = 500;
                            //port.Open();   //open all port
                            //add to list
                            listCom.Add(port);
                            listHead.Add(dt.Rows[i]["read_head"].ToString());
                            listNode.Add(int.Parse(dt.Rows[i]["node_count"].ToString()));
                        }
                        catch (Exception ex)
                        {
                            SystemLogger.Write(ex);
                        }
                    }
                    sysStatus.IsChangCom = false;
                }
            }
            catch (Exception ex)
            {
                SystemLogger.Write(ex);
            }
        }
        private void StartDoThread()
        {
            if (doProcessThread == null)
            {
                doProcessThread = new Thread(new ThreadStart(DoProcess));
                doProcessThread.Name = "Temp Do Process Thread";
                doProcessThread.IsBackground = true;
                doProcessThread.Start();
            }
        }
        private void DoProcess()
        {
            while (true)
            {
                if (sysStatus.IsStartRead)
                {
                    DoProcessFun();
                }
                else
                {
                    Thread.Sleep(1000);
                }
            }
        }
        private void DoProcessFun()
        {
            lock (lockDoProcess)
            {
                DateTime startTime = DateTime.Now;
                try
                {
                    //1. check list data
                    if (listTempData.Count <= 0) return;
                    //2. get get one data
                    Meter_Str tempData = listTempData[0];
                    //3. analyse one data
                    int type;
                    if (tempData.Com_Port != "COM1" || tempData.Com_Port != "COM2")
                    {
                        type = 1;
                    }
                    else
                    {
                        type = 2;
                    }
                    Temperature_Str realData = AnalyseData(tempData.Meter_Data, "1");
                    //RealData_EQ600 realData = AnalyseData(tempData.Meter_Data, tempData.Param_Data);
                    //RealData_PMH630 realData = AnalyseData(tempData.Meter_Data, type); 
                    //4. save data to db
                    string hd_id = GetMeterID(tempData.Com_Port, tempData.Meter_Data.Substring(0, 2));
                    realData.hd_id = hd_id;
                    bool ret = SaveReal2DB(realData);
                    //5. delete from list
                    if (ret)
                    {
                        //success,delete one data
                        listTempData.RemoveAt(0);
                    }
                    else
                    {
                        //failed
                        SystemLogger.Write(LogType.Error, "Save to db failed,data:" + tempData.Meter_Data, "DoProcessFun");
                        //remove data
                        listTempData.RemoveAt(0);
                    }
                    //check time is at hour end
                    if (DateTime.Now.Hour > cur_hour)
                    {
                        if (DateTime.Now.Minute > 58)
                        {
                            SaveHourData2DB();
                            cur_hour = DateTime.Now.Hour;
                            if (cur_hour >= 23)
                            {
                                cur_hour = -1;
                            }
                        }
                    }
                    //6. do next data
                }
                catch (Exception ex)
                {
                    SystemLogger.Write(ex);
                }
                finally
                {
                    TimeSpan useTime = DateTime.Now - startTime;
                    SystemLogger.Write(LogType.Flow, "Do process time " + useTime.TotalMilliseconds, "DocProcess");
                    Thread.Sleep(500);
                }
            }
        }
        private Temperature_Str AnalyseData(string data1, string param1)
        {
            Temperature_Str ret = new Temperature_Str();
            try
            {                
                if (data1.Length < 10) return ret;
                //温度         
                //status
                ret.stat  = Convert.ToInt32(data1.Substring(6, 4), 16).ToString();

                //temperature                
                ret.t_a = (float)Convert.ToInt32(data1.Substring(10, 4), 16) -35;
                ret.t_b = (float)Convert.ToInt32(data1.Substring(14, 4), 16) -35;
                ret.t_c = (float)Convert.ToInt32(data1.Substring(18, 4), 16) -35;
                
                return ret;
            }
            catch (Exception ex)
            {
                SystemLogger.Write(ex);
                return ret;
            }
        }
        private string GetMeterID(string port, string node)
        {
            string ret = "";
            try
            {
                if (dtMeter == null || dtMeter.Rows.Count <= 0)
                {
                    dtMeter = meterBLL.GetList(" station_id='" + sysStatus.Station_id + "' ").Tables[0];
                }
                //根据com和node 查找id；
                int _node = Convert.ToInt32(node, 16);
                DataRow[] datarows = dtMeter.Select(" com_port ='" + port + "' and node ='" + _node + "' ");
                if (datarows.Length > 0)
                {
                    ret = datarows[0]["meter_id"].ToString();
                }
                return ret;
            }
            catch (Exception ex)
            {
                SystemLogger.Write(ex);
                return ret;
            }
        }

        private bool SaveReal2DB(Temperature_Str data)
        {
            bool ret = false;
            try
            {
                Model.Thermostat_r mR = realDataBLL.GetModel(data.hd_id,sysStatus.Station_id);
                if (mR == null)
                {
                    //new one
                    mR = new Model.Thermostat_r();
                    mR.hd_id = data.hd_id;
                    mR.stat = data.stat;
                    mR.station_id = sysStatus.Station_id;
                    mR.evt_time = DateTime.Now;
                    mR.t_a = (decimal)data.t_a;
                    mR.t_b = (decimal)data.t_b;
                    mR.t_c = (decimal)data.t_c;

                    ret = realDataBLL.Add(mR);
                }
                else
                {
                    //update one                    
                    mR.hd_id = data.hd_id;
                    mR.stat = data.stat;
                    mR.station_id = sysStatus.Station_id;
                    mR.evt_time = DateTime.Now;
                    mR.t_a = (decimal)data.t_a;
                    mR.t_b = (decimal)data.t_b;
                    mR.t_c = (decimal)data.t_c;

                    ret = realDataBLL.Update(mR);
                }
                return ret;
            }
            catch (Exception ex)
            {
                SystemLogger.Write(ex);
                return ret;
            }
        }
        private bool SaveHourData2DB()
        {
            bool ret = false;
            try
            {
                //do PROCEDURE

                IDataParameter[] parameter = new IDataParameter[1];
                parameter[0] = new System.Data.SqlClient.SqlParameter("@station_id", sysStatus.Station_id);
                //parameter[0] = sysStatus.Station_id;
                int count = 0;
                int cnt = DBUtility.DbHelperSQL.RunProcedure("proc_do_thermostat", parameter, out count);
                if (count > 0)
                {
                    ret = true;
                    SystemLogger.Write(LogType.Flow, "Temperature save hour data to db,count:" + count, "SaveHourData2DB");
                }
                return ret;
            }
            catch (Exception ex)
            {
                SystemLogger.Write(ex);
                return ret;
            }
        }

        #region interface
        public bool Start()
        {
            StartThread();
            StartDoThread();            
            sysStatus.IsStartRead = true;
            return true;
        }

        public bool Stop()
        {
            sysStatus.IsStartRead = false;
            return true;
        }
        public bool OpenPort()
        {
            bool ret = false;
            try
            {
                //open all port
                int count = 0;
                for (int i = 0; i < listCom.Count; i++)
                {
                    try
                    {
                        if (!listCom[i].IsOpen)
                        {
                            listCom[i].Open();
                            count++;
                        }
                    }
                    catch (Exception ex)
                    {
                        SystemLogger.Write(ex);
                    }
                }
                if (count == listCom.Count)
                {
                    ret = true;
                }
                return ret;
            }
            catch (Exception ex)
            {
                SystemLogger.Write(ex);
                return ret;
            }
        }
        public bool ClosePort()
        {
            bool ret = false;
            try
            {
                //open all port
                int count = 0;
                for (int i = 0; i < listCom.Count; i++)
                {
                    try
                    {
                        if (listCom[i].IsOpen)
                        {
                            listCom[i].Close();
                            count++;
                        }
                    }
                    catch (Exception ex)
                    {
                        SystemLogger.Write(ex);
                    }
                }
                if (count == listCom.Count)
                {
                    ret = true;
                }
                return ret;
            }
            catch (Exception ex)
            {
                SystemLogger.Write(ex);
                return ret;
            }
        }
        #endregion
    }
}
